using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Input;
using System.Collections.Generic;
using Tomahawk.Runtime.Player;
using System.Xml.Serialization;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Content;
using Tomahawk.Runtime.Components;
using Tomahawk.Runtime.Console;
using Tomahawk.Runtime.Resources;

namespace Tomahawk.Runtime.Input
{

    /// <summary>
    /// Delegate to notify a player detection
    /// </summary>
    public delegate void PlayerDetectionDelegate(PlayerIndex padIndex, bool isKeyboardActivated);

    /// <summary>
    /// Tomhawk input manager
    /// </summary>
    public class InputManager
    {
        #region "Types"

        /// <summary>
        /// Gamepad state controller
        /// </summary>
        public class GamePad
        {
            public bool Active;
            public PlayerIndex Index;
            public GamePadState CurrentState;
            public GamePadState PreviousState;
            public ButtonState[] LSDigitalCurrentState;
            public ButtonState[] LSDigitalPreviousState;
            public ButtonState[] RSDigitalCurrentState;
            public ButtonState[] RSDigitalPreviousState;

            /// <summary>
            /// Constructor
            /// </summary>
            public GamePad()
            {
                this.LSDigitalCurrentState = new ButtonState[(int)AnalogStickDigitalDirections.UpLeft + 1];
                this.LSDigitalPreviousState = new ButtonState[(int)AnalogStickDigitalDirections.UpLeft + 1];
                this.RSDigitalCurrentState = new ButtonState[(int)AnalogStickDigitalDirections.UpLeft + 1];
                this.RSDigitalPreviousState = new ButtonState[(int)AnalogStickDigitalDirections.UpLeft + 1];
            }
        }

        /// <summary>
        /// Runble effect definition
        /// </summary>
        public class RumbleEffect : Tomahawk.Runtime.Resources.LoadableResource
        {
            [XmlAttribute("name")]
            public string Name;

            [XmlElement("LeftCurve")]
            public string LeftCurveAsset;

            [XmlElement("RightCurve")]
            public string RightCurveAsset;

            [XmlElement("Duration")]
            public float Duration;

            /// <summary>
            /// Curve for the left motor
            /// </summary>
            [XmlIgnore()]
            public Curve LeftCurve;

            /// <summary>
            /// Curve for the right motor
            /// </summary>
            [XmlIgnore()]
            public Curve RightCurve;

            /// <summary>
            /// Loading of assets
            /// </summary>
            protected override bool OnLoad(GraphicsDevice graphics, ContentManager contentManager)
            {
                this.resourcePool = ResourceManager.ResourcePool.Global;
                this.LeftCurve = contentManager.Load<Curve>(this.LeftCurveAsset);
                this.RightCurve = contentManager.Load<Curve>(this.RightCurveAsset);
                return true;
            }
        }

        #endregion

        #region "Private properties"

        private GamePad[] gamePads = new GamePad[(int) (PlayerIndex.Four + 1)];

        private static KeyboardState emptyKeyState = new KeyboardState();

        private static GamePadState emptyPadState = new GamePadState();

        private KeyboardState previousKeyState;

        private KeyboardState currentKeyState;

        private MouseState previousMouseState;

        private MouseState currentMouseState;

        private bool vibrationEnabled = true;

        #endregion

        public InputManager()
        {
            //create and initialize the pads array
            PlayerIndex currIndex = PlayerIndex.One;
            for (int i = 0; i < 4; i++)
            {
                //add a pad to the list
                GamePad pad = new GamePad();
                pad.Active = false;
                pad.Index = currIndex;
                this.gamePads[(int) pad.Index] = pad;

                //next index
                if (currIndex == PlayerIndex.One) currIndex = PlayerIndex.Two;
                else if (currIndex == PlayerIndex.Two) currIndex = PlayerIndex.Three;
                else if (currIndex == PlayerIndex.Three) currIndex = PlayerIndex.Four;
            }

            //initialize rumble support
            this.initializeRumble();
        }

        #region "Player Detection Mode"

        private bool playerDetectionMode = false;

        /// <summary>
        /// Start the "player detection" mode
        /// </summary>
        public void StartPlayerDetectionMode()
        {
            this.playerDetectionMode = true;
        }

        /// <summary>
        /// End "player detection" mode
        /// </summary>
        public void EndPlayerDetectionMode()
        {
            this.playerDetectionMode = false;
        }

        public event PlayerDetectionDelegate PlayerDetected;

        #endregion

        /// <summary>
        /// Activate processing on a certain gamepad
        /// </summary>
        internal void ActivateKeypadProcessing(PlayerIndex gamePadIndex, bool isActive)
        {
            this.gamePads[(int) gamePadIndex].Active = isActive;
        }

        /// <summary>
        /// Update the gamepads states
        /// </summary>
        public void Update(float elapsedTime)
        {
            //
            //sample gamepads states
            //

            foreach (GamePad pad in this.gamePads)
            {
                //if this pad needs processing
                if (pad.Active || this.playerDetectionMode)
                {
                    if (!ConsoleComponent.IsActive)
                    {
                        //save the current state as previous one
                        pad.PreviousState = pad.CurrentState;

                        //get the new state
                        pad.CurrentState = Microsoft.Xna.Framework.Input.GamePad.GetState(pad.Index);

                        //sample digital-like behaviour
                        this.sampleDigitalLikeStates(pad);

                        //update vibration
                        this.updateRumbleSupport(pad.Index, elapsedTime);
                    }
                    else
                    {
                        //save the current state as previous one
                        pad.PreviousState = emptyPadState;

                        //get the new state
                        pad.CurrentState = emptyPadState;

                        //sample digital-like behaviour
                        this.sampleDigitalLikeStates(pad);

                        //update vibration
                        this.updateRumbleSupport(pad.Index, elapsedTime);
                    }
                }
            }

            //
            // keyboard
            //

            if (!ConsoleComponent.IsActive)
            {
                this.previousKeyState = this.currentKeyState;
                this.currentKeyState = Microsoft.Xna.Framework.Input.Keyboard.GetState();
            }
            else
            {
                this.previousKeyState = emptyKeyState;
                this.currentKeyState = emptyKeyState;
            }

            //
            // mouse
            //

            this.previousMouseState = this.currentMouseState;
            this.currentMouseState = Microsoft.Xna.Framework.Input.Mouse.GetState();

            //
            //player detection mode
            //

            if (this.playerDetectionMode)
            {
                //detect START button on gamepads
                foreach (GamePad pad in this.gamePads)
                {
                    if ((pad.CurrentState.Buttons.Start == ButtonState.Pressed)
                        && (pad.PreviousState.Buttons.Start == ButtonState.Released))
                    {
                        if (PlayerDetected != null) PlayerDetected(pad.Index, false);
                    }
                }
                //detect ENTER button on keyboard
                if (this.currentKeyState.IsKeyDown(Keys.Enter) && !this.previousKeyState.IsKeyDown(Keys.Enter))
                {
                    if (this.PlayerDetected != null) PlayerDetected(PlayerIndex.One, true);
                }
            }

        }

        #region "Enumerations"

        public enum THDPadKeys
        {
            Up,
            Down,
            Left,
            Right
        }

        public enum THGamePadButtons
        {
            A,
            B,
            Back,
            BigButton,
            LeftShoulder,
            LeftStick,
            RightShoulder,
            RightStick,
            Start,
            X,
            Y
        }

        public enum THMouseButtons
        {
            Left,
            Middle,
            Right
        }

        #endregion

        #region "Key and Button tests (discrete keypress simulation)"

        /// <summary>
        /// Utility to test if gamepad DPAD button was pressed
        /// </summary>
        public bool TestDPadButtonPressed(PlayerIndex index, THDPadKeys key)
        {
            bool retVal = false;
            GamePad pad = this.gamePads[(int) index];
            if (pad.Active)
            {
                switch (key)
                {
                    case THDPadKeys.Down:
                        retVal = (pad.PreviousState.DPad.Down == ButtonState.Released) && (pad.CurrentState.DPad.Down == ButtonState.Pressed);
                        break;
                    case THDPadKeys.Left:
                        retVal = (pad.PreviousState.DPad.Left == ButtonState.Released) && (pad.CurrentState.DPad.Left == ButtonState.Pressed);
                        break;
                    case THDPadKeys.Right:
                        retVal = (pad.PreviousState.DPad.Right == ButtonState.Released) && (pad.CurrentState.DPad.Right == ButtonState.Pressed);
                        break;
                    case THDPadKeys.Up:
                        retVal = (pad.PreviousState.DPad.Up == ButtonState.Released) && (pad.CurrentState.DPad.Up == ButtonState.Pressed);
                        break;
                }
            }
            return retVal;
        }

        /// <summary>
        /// Utility to test if a certain button was pressed on a gamepad
        /// </summary>
        public bool TestButtonPressed(PlayerIndex index, THGamePadButtons button)
        {
            bool retVal = false;
            GamePad pad = this.gamePads[(int)index];
            if (pad.Active)
            {
                switch (button)
                {
                    case THGamePadButtons.A:
                        retVal = (pad.PreviousState.Buttons.A == ButtonState.Released) && (pad.CurrentState.Buttons.A == ButtonState.Pressed);
                        break;
                    case THGamePadButtons.B:
                        retVal = (pad.PreviousState.Buttons.B == ButtonState.Released) && (pad.CurrentState.Buttons.B == ButtonState.Pressed);
                        break;
                    case THGamePadButtons.Back:
                        retVal = (pad.PreviousState.Buttons.Back == ButtonState.Released) && (pad.CurrentState.Buttons.Back == ButtonState.Pressed);
                        break;
                    case THGamePadButtons.BigButton:
                        retVal = (pad.PreviousState.Buttons.BigButton == ButtonState.Released) && (pad.CurrentState.Buttons.BigButton == ButtonState.Pressed);
                        break;
                    case THGamePadButtons.LeftShoulder:
                        retVal = (pad.PreviousState.Buttons.LeftShoulder == ButtonState.Released) && (pad.CurrentState.Buttons.LeftShoulder == ButtonState.Pressed);
                        break;
                    case THGamePadButtons.LeftStick:
                        retVal = (pad.PreviousState.Buttons.LeftStick == ButtonState.Released) && (pad.CurrentState.Buttons.LeftStick == ButtonState.Pressed);
                        break;
                    case THGamePadButtons.RightShoulder:
                        retVal = (pad.PreviousState.Buttons.RightShoulder == ButtonState.Released) && (pad.CurrentState.Buttons.RightShoulder == ButtonState.Pressed);
                        break;
                    case THGamePadButtons.RightStick:
                        retVal = (pad.PreviousState.Buttons.RightStick == ButtonState.Released) && (pad.CurrentState.Buttons.RightStick == ButtonState.Pressed);
                        break;
                    case THGamePadButtons.Start:
                        retVal = (pad.PreviousState.Buttons.Start == ButtonState.Released) && (pad.CurrentState.Buttons.Start == ButtonState.Pressed);
                        break;
                    case THGamePadButtons.X:
                        retVal = (pad.PreviousState.Buttons.X == ButtonState.Released) && (pad.CurrentState.Buttons.X == ButtonState.Pressed);
                        break;
                    case THGamePadButtons.Y:
                        retVal = (pad.PreviousState.Buttons.Y == ButtonState.Released) && (pad.CurrentState.Buttons.Y == ButtonState.Pressed);
                        break;
                }
            }
            return retVal;
        }

        /// <summary>
        /// Utility to get the current mouse cursor position
        /// </summary>
        /// <returns></returns>
        public Vector2 GetMouseCursorPosition()
        {
            Vector2 position = Vector2.Zero;
            position.X = currentMouseState.X;
            position.Y = currentMouseState.Y;
            return position;
        }

        /// <summary>
        /// Utility to get the current mouse cursor displacement
        /// </summary>
        /// <returns></returns>
        public Vector2 GetMouseCursorDisplacement()
        {
            Vector2 displacement = Vector2.Zero;
            displacement.X = currentMouseState.X - previousMouseState.X;
            displacement.Y = currentMouseState.Y - previousMouseState.Y;
            return displacement;
        }

        /// <summary>
        /// Utility to get the current mouse wheel position
        /// </summary>
        /// <returns></returns>
        public int GetMouseWheelPosition()
        {
            return currentMouseState.ScrollWheelValue;
        }

        /// <summary>
        /// Utility to get the current mouse wheel position
        /// </summary>
        /// <returns></returns>
        public int GetMouseWheelDisplacement()
        {
            return currentMouseState.ScrollWheelValue - previousMouseState.ScrollWheelValue;
        }

        /// <summary>
        /// Utility to test if a certain mouse button was pressed
        /// </summary>
        public bool TestMouseButtonPressed(THMouseButtons button)
        {
            bool retVal = false;
            switch (button)
            {
                case THMouseButtons.Left:
                    retVal = (previousMouseState.LeftButton == ButtonState.Released) && (currentMouseState.LeftButton == ButtonState.Pressed);
                    break;
                case THMouseButtons.Middle:
                    retVal = (previousMouseState.MiddleButton == ButtonState.Released) && (currentMouseState.MiddleButton == ButtonState.Pressed);
                    break;
                case THMouseButtons.Right:
                    retVal = (previousMouseState.RightButton == ButtonState.Released) && (currentMouseState.RightButton == ButtonState.Pressed);
                    break;
            }

            return retVal;
        }

        /// <summary>
        /// Utility to test if a certain mouse button was released
        /// </summary>
        public bool TestMouseButtonReleased(THMouseButtons button)
        {
            bool retVal = false;
            switch (button)
            {
                case THMouseButtons.Left:
                    retVal = (previousMouseState.LeftButton == ButtonState.Pressed) && (currentMouseState.LeftButton == ButtonState.Released);
                    break;
                case THMouseButtons.Middle:
                    retVal = (previousMouseState.MiddleButton == ButtonState.Pressed) && (currentMouseState.MiddleButton == ButtonState.Released);
                    break;
                case THMouseButtons.Right:
                    retVal = (previousMouseState.RightButton == ButtonState.Pressed) && (currentMouseState.RightButton == ButtonState.Released);
                    break;
            }

            return retVal;
        }

        /// <summary>
        /// Utility to test if a certain key was pressed
        /// </summary>
        public bool TestKeyboardPressed(Keys key)
        {
            bool retVal = false;
            retVal = previousKeyState.IsKeyUp(key) && currentKeyState.IsKeyDown(key);
            return retVal;
        }

        /// <summary>
        /// Utility to test if a certain key was released
        /// </summary>
        public bool TestKeyboardReleased(Keys key)
        {
            bool retVal = false;
            retVal = previousKeyState.IsKeyDown(key) && currentKeyState.IsKeyUp(key);
            return retVal;
        }
        #endregion

        #region "Get Key and Button state (continuous state)"

        /// <summary>
        /// Get if a certain key is down
        /// </summary>
        public bool GetKeyboardIsDown(Keys key)
        {
            return this.currentKeyState.IsKeyDown(key);
        }

        /// <summary>
        /// Get if a certain key is up
        /// </summary>
        public bool GetKeyboardIsUp(Keys key)
        {
            return this.currentKeyState.IsKeyUp(key);
        }

        /// <summary>
        /// Get the current state of a mouse button
        /// </summary>
        public ButtonState GetMouseButtonState(THMouseButtons button)
        {
            ButtonState retVal = ButtonState.Released;
            switch (button)
            {
                case THMouseButtons.Left:
                    retVal = currentMouseState.LeftButton;
                    break;
                case THMouseButtons.Middle:
                    retVal = currentMouseState.MiddleButton;
                    break;
                case THMouseButtons.Right:
                    retVal = currentMouseState.RightButton;
                    break;
            }

            return retVal;
        }

        /// <summary>
        /// Get the state of the gamepad buttons
        /// </summary>
        public GamePadButtons GetGamePadButtonState(PlayerIndex index)
        {
            return this.gamePads[(int)index].CurrentState.Buttons;
        }

        /// <summary>
        /// Get the state of the gamepad DPad
        /// </summary>
        public GamePadDPad GetGamePadDPad(PlayerIndex index)
        {
            return this.gamePads[(int)index].CurrentState.DPad;
        }

        /// <summary>
        /// Get the state of the gamepad thumbsticks
        /// </summary>
        public GamePadThumbSticks GetGamePadThumbsticks(PlayerIndex index)
        {
            return this.gamePads[(int)index].CurrentState.ThumbSticks;
        }

        /// <summary>
        /// Get the state of the gamepad triggers
        /// </summary>
        public GamePadTriggers GetGamePadTriggers(PlayerIndex index)
        {
            return this.gamePads[(int)index].CurrentState.Triggers;
        }

        /// <summary>
        /// Get the full state of a gamepad
        /// </summary>
        public GamePadState GetGamePadFullState(PlayerIndex index)
        {
            return this.gamePads[(int)index].CurrentState;
        }

        /// <summary>
        /// Get the state of the gamepad buttons
        /// </summary>
        public GamePadButtons GetGamePadButtonState(PlayerManager.Player player)
        {
            return this.gamePads[(int)player.GamepadIndex].CurrentState.Buttons;
        }

        /// <summary>
        /// Get the state of the gamepad DPad
        /// </summary>
        public GamePadDPad GetGamePadDPad(PlayerManager.Player player)
        {
            return this.gamePads[(int)player.GamepadIndex].CurrentState.DPad;
        }

        /// <summary>
        /// Get the state of the gamepad thumbsticks
        /// </summary>
        public GamePadThumbSticks GetGamePadThumbsticks(PlayerManager.Player player)
        {
            return this.gamePads[(int)player.GamepadIndex].CurrentState.ThumbSticks;
        }

        /// <summary>
        /// Get the state of the gamepad triggers
        /// </summary>
        public GamePadTriggers GetGamePadTriggers(PlayerManager.Player player)
        {
            return this.gamePads[(int)player.GamepadIndex].CurrentState.Triggers;
        }

        /// <summary>
        /// Get the full state of a gamepad
        /// </summary>
        public GamePadState GetGamePadFullState(PlayerManager.Player player)
        {
            return this.gamePads[(int)player.GamepadIndex].CurrentState;
        }

        #endregion

        #region "Digital-Like behavior for Analog sticks"

        private float H_THRESHOLD = 0.15f;

        private float V_THRESHOLD = 0.15f;

        /// <summary>
        /// Available analog sticks
        /// </summary>
        public enum AnalogSticks
        {
            Left,
            Right
        }

        /// <summary>
        /// Available analog sticks digital-like directions
        /// </summary>
        public enum AnalogStickDigitalDirections
        {
            Up = 0,
            UpRight,
            Right,
            DownRight,
            Down,
            DownLeft,
            Left,
            UpLeft,
        }

        /// <summary>
        /// Sample current state of the analog sticks and deduce its digital-like state
        /// </summary>
        private void sampleDigitalLikeStates(GamePad pad)
        {
            //
            //copy current state to previous
            //

            for (int i = 0; i <= (int)AnalogStickDigitalDirections.UpLeft; i++)
            {
                pad.LSDigitalPreviousState[i] = pad.LSDigitalCurrentState[i];
                pad.RSDigitalPreviousState[i] = pad.RSDigitalCurrentState[i];
            }

            //
            // sample new states (LS)
            //

            bool isUp = false;
            bool isDown = false;
            bool isLeft = false;
            bool isRight = false;

            //default to released state
            pad.LSDigitalCurrentState[(int)AnalogStickDigitalDirections.Down] = ButtonState.Released;
            pad.LSDigitalCurrentState[(int)AnalogStickDigitalDirections.DownLeft] = ButtonState.Released;
            pad.LSDigitalCurrentState[(int)AnalogStickDigitalDirections.DownRight] = ButtonState.Released;
            pad.LSDigitalCurrentState[(int)AnalogStickDigitalDirections.Left] = ButtonState.Released;
            pad.LSDigitalCurrentState[(int)AnalogStickDigitalDirections.Right] = ButtonState.Released;
            pad.LSDigitalCurrentState[(int)AnalogStickDigitalDirections.Up] = ButtonState.Released;
            pad.LSDigitalCurrentState[(int)AnalogStickDigitalDirections.UpLeft] = ButtonState.Released;
            pad.LSDigitalCurrentState[(int)AnalogStickDigitalDirections.UpRight] = ButtonState.Released;

            isRight = (pad.CurrentState.ThumbSticks.Left.X > H_THRESHOLD);
            isLeft = (pad.CurrentState.ThumbSticks.Left.X < (H_THRESHOLD * -1));
            isUp = (pad.CurrentState.ThumbSticks.Left.Y > V_THRESHOLD);
            isDown = (pad.CurrentState.ThumbSticks.Left.Y < (V_THRESHOLD * -1));

            if (isUp)
            {
                if (isLeft)
                {
                    pad.LSDigitalCurrentState[(int)AnalogStickDigitalDirections.UpLeft] = ButtonState.Pressed;
                }
                else if (isRight)
                {
                    pad.LSDigitalCurrentState[(int)AnalogStickDigitalDirections.UpRight] = ButtonState.Pressed;
                }
                else
                {
                    pad.LSDigitalCurrentState[(int)AnalogStickDigitalDirections.Up] = ButtonState.Pressed;
                }
            }
            else if (isDown)
            {
                if (isLeft)
                {
                    pad.LSDigitalCurrentState[(int)AnalogStickDigitalDirections.DownLeft] = ButtonState.Pressed;
                }
                else if (isRight)
                {
                    pad.LSDigitalCurrentState[(int)AnalogStickDigitalDirections.DownRight] = ButtonState.Pressed;
                }
                else
                {
                    pad.LSDigitalCurrentState[(int)AnalogStickDigitalDirections.Down] = ButtonState.Pressed;
                }
            }
            else
            {
                if (isLeft)
                {
                    pad.LSDigitalCurrentState[(int)AnalogStickDigitalDirections.Left] = ButtonState.Pressed;
                }
                else if (isRight)
                {
                    pad.LSDigitalCurrentState[(int)AnalogStickDigitalDirections.Right] = ButtonState.Pressed;
                }
            }

            //
            // sample new states (RS)
            //

            //default to released state
            pad.RSDigitalCurrentState[(int)AnalogStickDigitalDirections.Down] = ButtonState.Released;
            pad.RSDigitalCurrentState[(int)AnalogStickDigitalDirections.DownLeft] = ButtonState.Released;
            pad.RSDigitalCurrentState[(int)AnalogStickDigitalDirections.DownRight] = ButtonState.Released;
            pad.RSDigitalCurrentState[(int)AnalogStickDigitalDirections.Left] = ButtonState.Released;
            pad.RSDigitalCurrentState[(int)AnalogStickDigitalDirections.Right] = ButtonState.Released;
            pad.RSDigitalCurrentState[(int)AnalogStickDigitalDirections.Up] = ButtonState.Released;
            pad.RSDigitalCurrentState[(int)AnalogStickDigitalDirections.UpLeft] = ButtonState.Released;
            pad.RSDigitalCurrentState[(int)AnalogStickDigitalDirections.UpRight] = ButtonState.Released;

            isRight = (pad.CurrentState.ThumbSticks.Right.X > H_THRESHOLD);
            isLeft = (pad.CurrentState.ThumbSticks.Right.X < (H_THRESHOLD * -1));
            isUp = (pad.CurrentState.ThumbSticks.Right.Y > V_THRESHOLD);
            isDown = (pad.CurrentState.ThumbSticks.Right.Y < (V_THRESHOLD * -1));

            if (isUp)
            {
                if (isLeft)
                {
                    pad.RSDigitalCurrentState[(int)AnalogStickDigitalDirections.UpLeft] = ButtonState.Pressed;
                }
                else if (isRight)
                {
                    pad.RSDigitalCurrentState[(int)AnalogStickDigitalDirections.UpRight] = ButtonState.Pressed;
                }
                else
                {
                    pad.RSDigitalCurrentState[(int)AnalogStickDigitalDirections.Up] = ButtonState.Pressed;
                }
            }
            else if (isDown)
            {
                if (isLeft)
                {
                    pad.RSDigitalCurrentState[(int)AnalogStickDigitalDirections.DownLeft] = ButtonState.Pressed;
                }
                else if (isRight)
                {
                    pad.RSDigitalCurrentState[(int)AnalogStickDigitalDirections.DownRight] = ButtonState.Pressed;
                }
                else
                {
                    pad.RSDigitalCurrentState[(int)AnalogStickDigitalDirections.Down] = ButtonState.Pressed;
                }
            }
            else
            {
                if (isLeft)
                {
                    pad.RSDigitalCurrentState[(int)AnalogStickDigitalDirections.Left] = ButtonState.Pressed;
                }
                else if (isRight)
                {
                    pad.RSDigitalCurrentState[(int)AnalogStickDigitalDirections.Right] = ButtonState.Pressed;
                }
            }

        }

        /// <summary>
        /// Utility to test a digital-like operation in an analog stick
        /// </summary>
        public bool TestAnalogStickDigitalDirection(PlayerIndex index, AnalogSticks stick, AnalogStickDigitalDirections direction)
        {
            bool retVal = false;
            GamePad pad = this.gamePads[(int)index];

            if (stick == AnalogSticks.Left)
            {
                if ((pad.LSDigitalCurrentState[(int)direction] == ButtonState.Pressed)
                    && (pad.LSDigitalPreviousState[(int)direction] == ButtonState.Released))
                    retVal = true;
            }
            else
            {
                if ((pad.RSDigitalCurrentState[(int)direction] == ButtonState.Pressed)
                    && (pad.RSDigitalCurrentState[(int)direction] == ButtonState.Released))
                    retVal = true;
            }

            return retVal;
        }


        #endregion

        #region "Rumble"

        public bool VibrationEnabled
        {
            get { return this.vibrationEnabled; }
            set { this.vibrationEnabled = value; }
        }

        private class PadRumbleEffect
        {
            public bool Active = false;
            public RumbleEffect RumbleEffect;
            public PlayerIndex GamePadIndex;

            private float accumTime = 0.0f;

            /// <summary>
            /// Evaluate curve values
            /// </summary>
            public void Evaluate(float elapsedTime, out float left, out float right)
            {
                this.accumTime+=elapsedTime;
                if (this.accumTime < this.RumbleEffect.Duration)
                {
                    left = this.RumbleEffect.LeftCurve.Evaluate(this.accumTime);
                    right = this.RumbleEffect.RightCurve.Evaluate(this.accumTime);
                }
                else
                {
                    this.Active = false;
                    left = 0.0f;
                    right = 0.0f;
                }
            }

        }

        private PadRumbleEffect[] activeRumbleEffects;

        /// <summary>
        /// Add a rumble effect to be played
        /// </summary>
        public void PlayRumbleEffect(RumbleEffect effect, PlayerIndex gamePadIndex)
        {
            if (this.vibrationEnabled)
            {
                //create a PadRumbleEffect struct 
                PadRumbleEffect padRumble = new PadRumbleEffect();
                padRumble.Active = true;
                padRumble.GamePadIndex = gamePadIndex;
                padRumble.RumbleEffect = effect;

                //add to pad
                this.activeRumbleEffects[(int)gamePadIndex] = padRumble;
            }
        }

        /// <summary>
        /// Initialize the array an necesary struct of the rumble support
        /// </summary>
        private void initializeRumble()
        {
            //rumble effect list
            this.activeRumbleEffects = new PadRumbleEffect[4];
            this.activeRumbleEffects[0] = new PadRumbleEffect();
            this.activeRumbleEffects[1] = new PadRumbleEffect();
            this.activeRumbleEffects[2] = new PadRumbleEffect();
            this.activeRumbleEffects[3] = new PadRumbleEffect();
        }

        /// <summary>
        /// Update the rumble effect for a concrete gamepad
        /// </summary>
        private void updateRumbleSupport(PlayerIndex gamePad, float elapsedTime)
        {
            int gPad = (int)gamePad;
            if ((this.activeRumbleEffects[gPad] != null) && (this.activeRumbleEffects[gPad].Active) && this.vibrationEnabled)
            {
                float left, right;
                this.activeRumbleEffects[(int)gamePad].Evaluate(elapsedTime, out left, out right);
                Microsoft.Xna.Framework.Input.GamePad.SetVibration(gamePad, left, right);
            }
            else
            {
                this.activeRumbleEffects[gPad] = null;
                Microsoft.Xna.Framework.Input.GamePad.SetVibration(gamePad, 0.0f, 0.0f);
            }
        }

        #endregion

    }

}
